/**
 * Namespace object
 */
var Rein = {};


(function($) {
    Rein.htmlEncode = function(value) {
        return $('<div/>').text(value).html();
    }
})(jQuery);


(function($) {
    Rein.Listbox = function(containerEl) {
        
        this.init = function(containerEl) {
            this.$containerEl = $(containerEl);
            this.jQueryDataKey = 'ReinListbox-data';
            this.cssClassItem = 'ReinListbox-item';
            this.cssClassSelected = 'ReinListbox-selected';
            this.$selectedItem = $('<div></div>');
            
            $.each(this.$containerEl.children(), $.proxy(function(index, element) {
                $(element).addClass(this.cssClassItem);
            }, this));
            
            this.$containerEl.on('click', '.' + this.cssClassItem, $.proxy(function(event){
                this.performSelect($(event.currentTarget));
            }, this));
        }
        
        this.select = function(value) {
            $.each(this.$containerEl.children(), $.proxy(function(index, child) {
                $child = $(child);
                if ($child.data(this.jQueryDataKey) == value) {
                    this.performSelect($child);
                }
            }, this));
        }
        
        this.performSelect = function($element) {
            if ($element.get(0) !== this.$selectedItem.get(0)) {
                this.$selectedItem.removeClass(this.cssClassSelected);
                this.$selectedItem = $element;
                this.$selectedItem.addClass(this.cssClassSelected);
                $(this).trigger('select');
            }
        }
        
        this.addItem = function(value, label) {
            var $item = $('<div>' + label + '</div>');
            $item.addClass(this.cssClassItem);
            $item.data(this.jQueryDataKey, value);
            this.$containerEl.append($item);
            return $item;
        }
        
        this.getSelectedValue = function() {
            return this.$selectedItem.data(this.jQueryDataKey);
        }
        
        this.init(containerEl);
    }
})(jQuery);


(function($) {
    Rein.TreeListbox = function(containerEl) {
        
        this.init = function(containerEl) {
            this.$containerEl = $(containerEl);
            this.jQueryDataKey = 'ReinListbox-data';
            this.cssClassItem = 'ReinListbox-item';
            this.cssClassSelected = 'ReinListbox-selected';
            this.$selectedItem = $('<div></div>');
            this.indentPixels = 20;
            
            $.each(this.$containerEl.children(), $.proxy(function(index, element) {
                $(element).addClass(this.cssClassItem);
            }, this));
            
            this.$containerEl.on('click', '.' + this.cssClassItem, $.proxy(this.handleItemClick, this));
        }
        
        this.select = function(value) {
            $.each(this.$containerEl.children(), $.proxy(function(index, child) {
                $child = $(child);
                if ($child.data(this.jQueryDataKey) == value) {
                    this.performSelect($child);
                }
            }, this));
        }
        
        this.performSelect = function($element) {
            if ($element.get(0) !== this.$selectedItem.get(0)) {
                this.$selectedItem.removeClass(this.cssClassSelected);
                this.$selectedItem = $element;
                this.$selectedItem.addClass(this.cssClassSelected);
                $(this).trigger('select');
            }
        }
        
        this.handleItemClick = function(event) {
            var $clickedItem = $(event.currentTarget);
            if ($clickedItem.get(0) !== this.$selectedItem.get(0)) {
                this.$selectedItem.removeClass(this.cssClassSelected);
                this.$selectedItem = $clickedItem;
                this.$selectedItem.addClass(this.cssClassSelected);
                $(this).trigger('select');
            }
        }
        
        this.addItem = function(value, label, level) {
            var $item = $('<div>' + Rein.htmlEncode(label) + '</div>');
            $item.addClass(this.cssClassItem);
            $item.data(this.jQueryDataKey, value);
            $item.css('padding-left', level * this.indentPixels);
            this.$containerEl.append($item);
        }
        
        this.selectFirst = function() {
            this.$selectedItem.removeClass(this.cssClassSelected);
            this.$selectedItem = this.$containerEl.children(":first");
            this.$selectedItem.addClass(this.cssClassSelected);
            $(this).trigger('select');
        }
        
        this.getSelectedValue = function() {
            return this.$selectedItem.data(this.jQueryDataKey);
        }
        
        this.clear = function() {
            this.$containerEl.empty();
            this.$selectedItem = $('<div></div>');
        }
        
        this.init(containerEl);
    }
})(jQuery);


(function($) {
    Rein.ScrollableTable = function(originalTable, options) {
        
        this.init = function(originalTable, options) {
            
            this.options = null;
            this.$container = null;
            this.$tableHeader = null;
            this.$scrollArea = null;
            this.$table = null;
            this.$selectedRow = $('<tr></tr>');
            this.jQueryDataKey = 'ReinTable-data';
            
            this.options = $.extend({
                headers: [],
                width: 'auto',
                height: 'auto',
                rowCssClass: 'ReinTable-Row',
                selectedCssClass: 'ReinTable-RowSelected',
                wrapperCssClass: 'ReinTable-Wrapper',
                headerCssClass: 'ReinTable-Header'
            }, options);
            
            var $originalTable = $(originalTable);
            
            // Create parts
            this.$container = $('<div></div>', {
                'class': this.options.wrapperCssClass,
                css: {width: this.options.width}
            });
            
            this.$tableHeader = $('<table></table>', {
                'class': this.options.headerCssClass,
                css: {width: '100%'}
            }).append('<tr></tr>');
            
            this.$scrollArea = $('<div></div>', {
                css: {
                    'overflow-y': 'scroll',
                    height: this.options.height
                }
            });
            
            this.$table = $("<table></table>", {
                id: $originalTable.attr('id'),
                css: {width: "100%"}
            });
            
            // Combine parts
            $originalTable.replaceWith(this.$container);
            this.$container.append(this.$tableHeader);
            this.$container.append(this.$scrollArea);
            this.$scrollArea.append(this.$table);
            
            this.setHeaders(this.options.headers);
            this.repairColumns();
            
            this.$table.on('click', '.' + this.options.rowCssClass, $.proxy(this.handleRowClick, this));
        }
        
        this.handleRowClick = function(event) {
            var $clickedRow = $(event.currentTarget);
            
            if ($clickedRow.get(0) !== this.$selectedRow.get(0)) {
                this.$selectedRow.removeClass(this.options.selectedCssClass);
                this.$selectedRow = $clickedRow;
                this.$selectedRow.addClass(this.options.selectedCssClass);
                $(this).trigger('select');
            }
        }
        
        this.getSelectedValue = function() {
            return this.$selectedRow.data(this.jQueryDataKey);
        }
        
        this.selectFirst = function() {
            this.$selectedRow.removeClass(this.selectedCssClass);
            this.$selectedRow = this.$table.find("tr:first");
            this.$selectedRow.addClass(this.options.selectedCssClass);
            $(this).trigger('select');
        }
        
        this.addRow = function(data, value) {
            
            var $newRow = $('<tr></tr>', {
                'class': this.options.rowCssClass
            });
            $newRow.data(this.jQueryDataKey, value);
            $(data).each(function(i){
                $newRow.append('<td>' + Rein.htmlEncode(data[i]) + '</td>');
            });
            
            this.$table.append($newRow);
            this.repairColumns();
        }
        
        this.clear = function() {
            this.$table.empty();
            this.$selectedRow = $('<tr></tr>');
        }
        
        this.setHeaders = function(headerNames) {
            if(headerNames.length > 0) {
                this.$tableHeader.find("tr").empty();
                $.each(headerNames, $.proxy(function(i, headerName){
                    var th = "<th>" + headerName + "</th>";
                    this.$tableHeader.find("tr").append(th);
                }, this));
            }
        }
        
        this.repairColumns = function() {
            var tr = this.$table.find('tr:first');
            var headerTr = this.$tableHeader.find('tr');

            tr.find('td').each(function(i) {
                if(i <= 1) {
                    $(headerTr.find('th')[i]).width($(tr.find('td')[i]).width());
                }
            });
        }
        
        this.getNumItems = function() {
            return this.$table.children().length;
        }
        
        this.init(originalTable, options);
    }
    
})(jQuery);


(function($) {
    Rein.SelectFolderDialog = function(inputEl, fnFolderFilter) {
        
        this.init = function(inputEl, fnFolderFilter) {
            
            this.folderMap = {};
            this.fnFolderFilter = fnFolderFilter;
            
            // 1.) Create form controls
            
            // Hide original input element
            this.$txtInput = $(inputEl);
            this.$txtInput.css('display', 'none');
            
            // Create disabled input to display current selection
            this.$txtDispSelected = $('<input type="text" disabled="disabled">');
            
            // Create the "Browse" button
            this.$btnActivate = $('<button type="button">Browse</button>');
            this.$btnActivate.on('click', $.proxy(this.open, this));
            
            // Insert controls into the DOM
            this.$txtInput.after(this.$btnActivate);
            this.$txtInput.after(this.$txtDispSelected);
            
            this.$txtDispSelected.val(this.$txtInput.data('foldername'));
            
            // 2.) Create dialog stuff
            
            // The HTML content of the dialog
            this.modalHtml = '<div>'
                                + '<h2>Select folder</h2>'
                                + '<table class="tblForm"><tr><td><div id="modal-lbxSelectFolder" class="ReinListbox" style="height: 280px; width: 310px;"></div>'
                                + '<button id="modal-btnSelect">Select</button></td></tr></table>'
                                + '<a class="simplemodal-close" href="#">Close</a>'
                            + '</div>';
            
            // Controls inside the dialog
            this.lbx = null;
            this.$btnSave = null;
        }
        
        /**
         * Opens the dialog
         */
        this.open = function() {
            
            // Reset some fields
            this.folderMap = {};
            var $modalContent = $(this.modalHtml);
            
            // Call simple modal plugin
            $.modal($modalContent, {
                close: false,
                onShow: $.proxy(this.handleDialogShow, this)
            });
        }
        
        /**
         * Handler for when the dialog gets visible.
         * @param dialog. Dialog object, see SimpleModal plugin
         */
        this.handleDialogShow = function(dialog) {
            
            // Init tree listbox
            this.lbx = new Rein.TreeListbox($('#modal-lbxSelectFolder', dialog.data));

            // Init save button
            this.$btnSave = $('#modal-btnSelect', dialog.data);
            this.$btnSave.on('click', $.proxy(function(){

                // Get selected value from listbox
                // and lookup the folder object in the map
                var selectedFolderId = this.lbx.getSelectedValue();
                var selectedFolder = this.folderMap[selectedFolderId];

                // Update whats displayed
                // and update the real value in the invisible input
                this.$txtDispSelected.val(selectedFolder.name);
                this.$txtInput.val(selectedFolder.id);

                // Finally close the dialog
                $.modal.close();
            }, this));
            
            // Load the folders for display in tree listbox
            this.loadFolders();
        }
        
        /**
        * Requests folder tree from server,
        * server returns JSON
        */
        this.loadFolders = function() {
            $.ajax({
                url: 'GetFolderTree',
                type: 'GET',
                success: $.proxy(function(rootFolder) {
                    this.displayFolder(rootFolder, 0);
                    this.lbx.select(this.$txtInput.val());
                }, this),
                dataType: 'json'
            });
        }
        
        /**
        * Displays the folders recursively
        */
        this.displayFolder = function(folder, level) {
            
            if (!($.isFunction(this.fnFolderFilter) && this.fnFolderFilter(folder) == false)) {
                this.folderMap[folder.id] = folder;
                this.lbx.addItem(folder.id, folder.name, level);

                $.each(folder.childs, $.proxy(function(i, child){
                    this.displayFolder(child, level + 1);
                }, this));
            }
        }
        
        // Call init
        this.init(inputEl, fnFolderFilter);
    }
})(jQuery);


(function($) {
    
    Rein.ConfirmDialog = function(message, fnCallback) {
        
        this.init = function(message, fnCallback) {
            this.message = message;
            this.fnCallback = fnCallback;
            this.modalHtml = '<div>'
                                + '<h2>Please confirm</h2>'
                                + '<table class="tblForm"><tr><td>' + message + '<br>'
                                + '<button id="modal-btnConfirm">OK</button></td></tr></table>'
                                + '<a class="simplemodal-close" href="#">Close</a>'
                            + '</div>';
        }
        
        this.open = function() {
            
            var $modalContent = $(this.modalHtml);
            
            // Call simple modal plugin
            $.modal($modalContent, {
                close: false,
                onShow: $.proxy(this.handleDialogShow, this)
            });
        }
        
        this.handleDialogShow = function(dialog) {
            $('#modal-btnConfirm', dialog.data).on('click', $.proxy(function() {
                if ($.isFunction(this.fnCallback)) {
                    this.fnCallback();
                }
                $.modal.close();
            }, this));
        }
        
        this.init(message, fnCallback);
    }
})(jQuery);